/*
 * Copyright (C) 2008 Universidade Federal de Campina Grande
 *  
 * This file is part of OurGrid. 
 *
 * OurGrid is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free 
 * Software Foundation, either version 3 of the License, or (at your option) 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details. 
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.ourgrid.acceptance.worker;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;
import org.ourgrid.acceptance.util.worker.Req_004_Util;
import org.ourgrid.acceptance.util.worker.Req_087_Util;
import org.ourgrid.acceptance.util.worker.Req_088_Util;
import org.ourgrid.acceptance.util.worker.Req_090_Util;
import org.ourgrid.acceptance.util.worker.Req_092_Util;
import org.ourgrid.common.interfaces.Worker;
import org.ourgrid.common.interfaces.management.WorkerManagementClient;
import org.ourgrid.common.interfaces.to.WorkerStatus;
import org.ourgrid.reqtrace.ReqTest;
import org.ourgrid.worker.WorkerComponent;
import org.ourgrid.worker.WorkerConstants;

import br.edu.ufcg.lsd.commune.identification.ContainerID;
import br.edu.ufcg.lsd.commune.identification.DeploymentID;

@ReqTest(reqs="REQ092")
public class Req_092_Test extends WorkerAcceptanceTestCase {
	
	private DeploymentID peerID;
	private Req_004_Util req_004_Util = new Req_004_Util(getComponentContext());
	private Req_090_Util req_090_Util = new Req_090_Util(getComponentContext());
	private Req_092_Util req_092_Util = new Req_092_Util(getComponentContext());
	private Req_087_Util req_087_Util = new Req_087_Util(getComponentContext());
	private Req_088_Util req_088_Util = new Req_088_Util(getComponentContext());
	
	@Before
	public void setUp() throws Exception {
		super.setUp();
		String peerPubKey = workerAcceptanceUtil.simulateAuthentication();
		
		peerID = new DeploymentID(new ContainerID("username", "server", "module", peerPubKey), "peer");
		
	}

	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the master peer public key property: "publicKey1" and the idleness detector DISABLED;
	 *    2. A peer with the public key "publicKey222" sends a workForMyGrid message to the Worker;
	 *           * Verify if the following warn message was logged: "An unknown peer tried to command this Worker to work for a local consumer. This message was ignored. Unknown peer public key: [publicKey222]."
	 *    3. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    4. A peer with the public key "publicKey222" sends a workForMyGrid message to the Worker;
	 *           * Verify if the following warn message was logged: "An unknown peer tried to command this Worker to work for a local consumer. This message was ignored. Unknown peer public key: [publicKey222]."
	 *    5. Verify if the WORKER object is NOT bound
	 *    6. Pause the Worker;
	 *           * Verify if the following info message was logged: "Worker has been PAUSED."
	 *           * Verify if the following warn message was logged: "Status changed from IDLE to OWNER."
	 *           * Verify if the ControlClient received the operation succeed message
	 *    7. A peer with the public key "publicKey222" sends a workForMyGrid message to the Worker;
	 *           * Verify if the following warn message was logged: "An unknown peer tried to command this Worker to work for a local consumer. This message was ignored. Unknown peer public key: [publicKey222]."
	 *    8. Verify if the WORKER object is NOT bound
	 *    9. Resume the Worker;
	 *           * Verify if the following info message was logged: "Worker has been RESUMED."
	 *           * Verify if the following debug message was logged: "Status changed from OWNER to IDLE."
	 *           * Verify if the ControlClient received the operation succeed message
	 *   10. A peer with the public key "publicKey222" sends a workForMyGrid message to the Worker;
	 *           * Verify if the following warn message was logged: "An unknown peer tried to command this Worker to work for a local consumer. This message was ignored. Unknown peer public key: [publicKey222]."
	 *   11. Verify if the WORKER object is NOT bound
	 * 
	 */
	@ReqTest(test="AT-092.1", reqs="REQ092")
	@Test public void test_at_092_1_UnknownPeerDefinesWorkerToWorkForMyGrid() throws Exception {
		//Start Worker
		WorkerComponent component = req_004_Util.startWorker();
		
		//Unknown peer sends a workForMyGrid message to the worker - expect a warn to be logged
		req_092_Util.workForMyGrid(component, "publicKey222");
		
		//Set peer
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		//Unknown peer sends a workForMyGrid message to the worker - expect a warn to be logged
		req_092_Util.workForMyGrid(component, "publicKey222");
		
		//Verify if the WORKER object is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		//Pause worker
		req_087_Util.pauseIdleWorkerWithoutCleaning(component, wmc);
		
		//Resume the Worker
		req_088_Util.resumeWorker(component, wmc);
		
		//Unknown peer sends a workForMyGrid message to the worker - expect a warn to be logged
		req_092_Util.workForMyGrid(component, "publicKey222");
		
		//Verify if the WORKER object is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
	}
	
	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the master peer public key property: "publicKey1";
	 *    2. A peer with the public key "publicKey1" sends a workForMyGrid message to the Worker;
	 *           * Verify if the following debug message was logged: "The master Peer tried to manage this Worker before setting itself as manager of this Worker. This message was ignored."
	 *    3. Verify if the WORKER object is NOT bound
	 * 
	 */
	@ReqTest(test="AT-092.2", reqs="REQ092")
	@Test public void test_at_092_2_PeerWhichIsNotTheMasterPeerDefinesWorkerToWorkForMyGrid() throws Exception {
		//Start Worker
		WorkerComponent component = req_004_Util.startWorker();
		
		//Peer sends a workForMyGrid message to the Worker - expect a debug to be logged
		req_092_Util.workForMyGridBeforeSetPeer(component);
		
		//Verify if the WORKER object is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
	}
	
	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the idleness detector ENABLED;
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the OWNER status
	 *    3. The master peer sends a workForMyGrid message to the Worker;
	 *           * Verify if the following debug message was logged: "This Worker was commanded to work for a local consumer, but it is in the OWNER status. This message was ignored."
	 *    4. Verify if the WORKER object is NOT bound
	 * 
	 */
	@ReqTest(test="AT-092.3", reqs="REQ092")
	@Test public void test_at_092_3_PeerDefinesBusyWorkerToWorkForMyGrid() throws Exception {
		//Start Worker with idleness detector ENABLED
		WorkerComponent component = req_004_Util.startWorker(true);

		//Set peer
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.OWNER);
		
		//Peer sends a workForMyGrid message to the Worker - expect a debug to be logged
		req_092_Util.workForMyGridOnOwnerWorker(component, wmc);
		
		//Verify if the WORKER object is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
	}
	
	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the idleness detector DISABLED;
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. Verify if the WORKER object is NOT bound
	 *    4. The master peer sends a workForMyGrid message to the Worker;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPubKey]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    5. Verify if the WORKER object is bound
	 * 
	 */
	@ReqTest(test="AT-092.4", reqs="REQ092")
	@Test public void test_at_092_4_PeerDefinesIdleWorkerToWorkForMyGrid() throws Exception {
		//Start Worker with idleness detector DISABLED
		WorkerComponent component = req_004_Util.startWorker();

		//Set peer
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(
				component, peerID, WorkerStatus.IDLE);
		
		//Verify if the WORKER object is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		//Peer sends a workForMyGrid message to the Worker -
		// expect that Worker to send an allocated for mygrid status changed message
		req_092_Util.workForMyGridOnIdleWorker(component, wmc, "mgPubKey");
		req_092_Util.beginAllocationCompleted(component, wmc);
		
		//Verify if the WORKER object is bound
		assertTrue(isBound(component, WorkerConstants.WORKER, Worker.class));
	}
	
	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the idleness detector DISABLED;
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. The master peer sends a workForMyGrid message to the Worker;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPubKey]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    4. Verify if the WORKER object is bound, and get its DeploymentID(objIDA)
	 *    5. The master peer sends another workForMyGrid message to the Worker, with the same client public key;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPubKey]."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    6. Verify if the WORKER object is bound, and get its DeploymentID(objIDB)
	 *           * Expect ObjIDB to be different from objIDA
	 *    7. Verify if the WORKER object (objIDA) is NOT bound
	 *    8. The master peer sends another workForMyGrid message to the Worker, with a different public key;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPubKey2222]."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    9. Verify if the WORKER object is bound, and get its DeploymentID(objIDC)
	 *           * Expect ObjIDC to be different from objIDB
	 * 
	 */
	@ReqTest(test="AT-092.5", reqs="REQ092")
	@Test public void test_at_092_5_PeerDefinesAllocatedWorkerToWorkForMyGrid() throws Exception {
		//Start Worker with idleness detector DISABLED
		WorkerComponent component = req_004_Util.startWorker();

		//Set peer
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		//Peer sends a workForMyGrid message to the Worker -
		// expect that Worker to send an allocated for mygrid status changed message
		req_092_Util.workForMyGridOnIdleWorker(component, wmc, "mgPubKey");
		req_092_Util.beginAllocationCompleted(component, wmc);
		
		//Verify if the WORKER object is bound
		assertTrue(workerAcceptanceUtil.isWorkerBound());
		
		//Get WORKER DeploymentID
		DeploymentID workerAID = workerAcceptanceUtil.getWorkerDeployment().getDeploymentID();

		assertTrue(isBound(component, WorkerConstants.MODULE_NAME,
				WorkerConstants.WORKER, workerAID.getDeploymentNumber(), Worker.class));
		
		//Peer sends a workForMyGrid message to the Worker with same client publicKey
		// expect that Worker to send an allocated for mygrid status changed message
		req_092_Util.workForMyGridOnAllocatedForMyGridWorker(component, wmc, "mgPubKey");
		Worker worker = req_092_Util.beginAllocationCompleted(component, wmc);
		
		assertFalse(isBound(component, WorkerConstants.MODULE_NAME,
				WorkerConstants.WORKER, workerAID.getDeploymentNumber(), Worker.class));
		
		//Verify if the WORKER object is bound
		assertTrue(workerAcceptanceUtil.isWorkerBound());
		
		//Get WORKER DeploymentID
		DeploymentID workerBID = workerAcceptanceUtil.getWorkerDeployment().getDeploymentID();
		
		//Verify if workerA is not bound
		assertFalse(isBound(component, WorkerConstants.MODULE_NAME,
				WorkerConstants.WORKER, workerAID.getDeploymentNumber(), Worker.class));
		
		//Expect workerBID to be different from workerAID
		assertFalse(workerBID.equals(workerAID));
		
		//Peer sends a workForMyGrid message to the Worker with different client publicKey
		// expect that Worker to send an allocated for mygrid status changed message
		req_092_Util.workForMyGridOnAllocatedForMyGridWorker(component, wmc, "mgPubKey2222");
		worker = req_092_Util.beginAllocationCompleted(component, wmc);
		
		//Get WORKER DeploymentID
		DeploymentID workerCID = workerAcceptanceUtil.getWorkerDeployment().getDeploymentID();
		
		//Expect workerCID to be different from workerBID
		assertFalse(workerCID.equals(workerBID));
	}
	
	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the idleness detector DISABLED
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. The master peer sends a workForMyGrid message to the Worker;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPubKey]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 * 	  4. Resume the Worker;
	 *			 * Verify if the ControlClient received the operation succeed message
	 *    5. Verify if the WORKER object is bound
	 *    6. Pause the Worker;
	 *           * Verify if the following info message was logged: "Worker has been PAUSED."
	 *           * Verify if the following debug message was logged: "Status changed from ALLOCATED_FOR_MYGRID to OWNER."
	 *           * Expect the Worker to send the peer a status changed message, with the OWNER status
	 *           * Verify if the ControlClient received the operation succeed message
	 *    7. Verify if the WORKER object is NOT bound
	 *    8. Resume the Worker;
	 *           * Verify if the following info message was logged: "Worker has been RESUMED."
	 *           * Verify if the following debug message was logged: "Status changed from OWNER to IDLE."
	 *           * Verify if the ControlClient received the operation succeed message
	 *    9. Verify if the WORKER object is NOT bound
	 * 
	 */
	@ReqTest(test="AT-092.6", reqs="REQ092")
	@Test public void test_at_092_6_AllocatedWorkerIsPaused() throws Exception {
		//Start Worker with idleness detector DISABLED
		WorkerComponent component = req_004_Util.startWorker();

		//Set peer
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		//Peer sends a workForMyGrid message to the Worker -
		// expect that Worker to send an allocated for mygrid status changed message
		req_092_Util.workForMyGridOnIdleWorker(component, wmc, "mgPubKey");
		req_092_Util.beginAllocationCompleted(component, wmc);
		
		//Resume worker
		req_088_Util.resumeNotOwnerWorker(component);

		//Verify if the WORKER object is bound
		assertTrue(isBound(component, WorkerConstants.WORKER, Worker.class));

		//Pause worker
		req_087_Util.pauseAllocatedForMyGridWorker(component, wmc);
		
		//Verify if the WORKER object is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
		
		//Resume worker
		req_088_Util.resumeOwnerWorker(wmc, component);
		
		//Verify if the WORKER object is NOT bound
		assertFalse(isBound(component, WorkerConstants.WORKER, Worker.class));
	}
	
	/**
	 * This test contains the following steps:
	 * 
	 *    1. Start a Worker with the idleness detector DISABLED
	 *    2. The master peer sends a setPeer message to the Worker;
	 *           * Verify if the following info message was logged: The peer [peerID] set itself as manager of this Worker.
	 *           * Expect the Worker to send a status changed message to the peer, with the IDLE status
	 *    3. The master peer sends a workForMyGrid message to the Worker;
	 *           * Verify if the following info message was logged: "Peer commanded this Worker to work for a local consumer. Local consumer public key: [mgPubKey]."
	 *           * Verify if the following debug message was logged: "Status changed from IDLE to ALLOCATED_FOR_MYGRID."
	 *           * Expect the Worker to send the peer an allocated for mygrid status changed message, with a stub to the Worker remote object
	 *    4. Verify if the WORKER object is bound
	 *    5. The master peer sends again a setPeer message to the Worker;
	 * 	         * Verify if the following warn message was logged:  The peer [peerID] set itself as manager of this Worker. This message was ignored. Because the master peer did not notify fail.
	 * 
	 */
	@ReqTest(test="AT-092.7", reqs="REQ092")
	@Test public void test_at_092_7_AllocatedWorkerGetsNewMasterPeer() throws Exception {
		//Start Worker with idleness detector DISABLED
		WorkerComponent component = req_004_Util.startWorker();

		//Set peer
		WorkerManagementClient wmc = req_090_Util.setKnownPeer(component, peerID, WorkerStatus.IDLE);
		
		//Peer sends a workForMyGrid message to the Worker -
		// expect that Worker to send an allocated for mygrid status changed message
		req_092_Util.workForMyGridOnIdleWorker(component, wmc, "mgPubKey");
		req_092_Util.beginAllocationCompleted(component, wmc);
		
		//Verify if the WORKER object is bound
		assertTrue(workerAcceptanceUtil.isWorkerBound());
		
		//Set peer - expect a warn to be logged
		req_090_Util.setPeerByMasterPeerFromSameLocation(component, peerID, WorkerStatus.ALLOCATED_FOR_BROKER, wmc);
		
	}
}